--[[
title: commonlib
description: 全局CAPI函数
]]



function commonlib.NewEnv(env)
	return setmetatable({}, {
		__index = env or _G,
		__call = commonlib.NewEnv,
	});
end



-- ==============================window=========================

-- function commonlib.SetMainWindowScale(scale)
--     __CAPI__.SetWindowScale(scale);
-- end

-- function commonlib.GetMainWindowScale() 
--     return __CAPI__.GetWindowScale();
-- end

-- function commonlib.GetMainWindowWidthHeight() 
--     return __CAPI__.GetWindowWidthHeight(); 
-- end

-- function commonlib.GetPaint()
--     return __CAPI__.Paint;
-- end

-- function commonlib.StartTextInput()
--     __CAPI__.StartTextInput();
-- end

-- function commonlib.StopTextInput()
--     __CAPI__.StopTextInput();
-- end

-- function commonlib.SetTextInputPosition(x, y, w, h)
--     __CAPI__.SetTextInputRect(x or 0, y or 0, w or 0, h or 0);
-- end

-- 备份路径
commonlib.__root_directory__ = commonlib.GetRootDirectory();
commonlib.__storage_directory__ = commonlib.GetStorageDirectory();
commonlib.__package_directory__ = commonlib.GetPackageDirectory();
commonlib.__asset_directory__ = commonlib.GetAssetDirectory();
commonlib.__script_directory__ = commonlib.GetScriptDirectory();
commonlib.__path_alias_map__ = {
    ["@storage"] = commonlib.__storage_directory__,
    ["@package"] = commonlib.__package_directory__,
    ["@script"] = commonlib.__script_directory__,
};

-- 打印堆栈
function commonlib.debug_traceback(begin_depth, end_depth, errmsg)
    commonlib.LOG_DEBUG("=================debug_traceback begin=================");
    commonlib.LOG_DEBUG(errmsg);
    begin_depth = begin_depth or 2;
    end_depth = end_depth or 50;
    local last_function_name = "";
    for i = 1, end_depth do
	    local info = debug.getinfo(i, "nSl");
        local logmsg;
        if (not info or info == "") then break end
        if (info.what == "C") then
            logmsg = "C function: " .. last_function_name;
        else
            filepath = string.sub(info.source, 1, string.find(info.source, "\n", 1, true));
            filepath = string.gsub(filepath, "%s*$", "");
            filepath = string.gsub(filepath, "^%s*", "");
            logmsg = string.format("%s:%d %s", filepath, info.currentline, last_function_name);
        end
        last_function_name = info.name or "";
        if (i >= begin_depth) then commonlib.LOG_DEBUG(logmsg) end
    end
    commonlib.LOG_DEBUG("=================debug_traceback end=================");
end



-- 核心函数
function commonlib.exit(errmsg)
    if (errmsg ~= nil) then
        commonlib.LOG_ERROR(errmsg);
        commonlib.debug_traceback(3);
    end
    commonlib.Stop();
end

function commonlib.GetDirectory(filepath)
    return filepath and string.gsub(filepath, "([^\\/]*)$", "");
end

function commonlib.GetFileName(filepath)
    return filepath and string.match(filepath, "([^\\/]*)$");
end

function commonlib.SetPathAlias(alias, path)
    commonlib.__path_alias_map__[string.lower(alias)] = path or "";
end

-- 格式化文件名
function commonlib.GetFullPath(filepath, directory)
    local path = string.gsub(filepath or "", "(@[%w_]*)", function(alias)
        local path = commonlib.__path_alias_map__[string.lower(alias)];
        if (type(path) == "string") then return path end
        if (type(path) == "function") then return path() end
        return "";
    end)

    if (commonlib.IsAbsolutePath(path)) then return commonlib.FormatPath(path) end
    return commonlib.FormatPath((directory or commonlib.__root_directory__) .. "/" .. path);
end

function commonlib.IsAssetFilePath(filepath)
    return string.sub(filepath, 1, string.len(commonlib.__asset_directory__)) == commonlib.__asset_directory__;
end

function commonlib.IsScriptFilePath(filepath)
    return string.sub(filepath, 1, string.len(commonlib.__script_directory__)) == commonlib.__script_directory__;
end

commonlib.__commonlib_directory__ = commonlib.FormatPath(commonlib.__script_directory__ .. "/commonlib");
commonlib.__commonlib_filename__ = commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/init.lua");
commonlib.__modules__ = {};

-- 加载模块
function commonlib.import(filepath, directory, G)
    local full_path = commonlib.GetFullPath(filepath, directory);
    -- commonlib.LOG_DEBUG("import: " .. full_path .. " directory:" .. (directory or ""));

    commonlib.__modules__[full_path] = commonlib.__modules__[full_path] or {};
    local __module__ = commonlib.__modules__[full_path];
    if (__module__.__loaded__) then return __module__.__module__ end

    __module__.__filename__ = full_path;
    __module__.__directory__ = commonlib.GetDirectory(full_path);
    __module__.__loaded__ = true;
    __module__.require = function (module_name) return commonlib.require(module_name, __module__.__directory__) end
    __module__.import = function(lua_filepath) return commonlib.import(lua_filepath, __module__.__directory__) end
    __module__.loadstring = function (lua_script) return commonlib.loadstring(lua_script, __module__, __module__.__filename__) end
    __module__.dostring = function (lua_script, start_line) return commonlib.dostring(lua_script, __module__, __module__.__filename__, nil, start_line) end
    setmetatable(__module__, {__index = G or _G});

    local filetext = commonlib.GetScriptTextByFilePath(full_path);
    local script_directory = commonlib.GetScriptDirectory();
    local script_disk_directory = commonlib.GetScriptDiskDirectory();
    local disk_path = full_path;
    if (script_disk_directory ~= "" and string.find(filepath, script_directory, 1, true) == 1) then
        disk_path = script_disk_directory .. string.sub(filepath, string.len(script_directory) + 1);
    end

    local func, errmsg = _G.load(filetext, disk_path, "bt", __module__);
    if (not func) then
        commonlib.LOG_WARN(errmsg);
        commonlib.LOG_WARN("ERROR: loadfile failed:" .. full_path);
        return nil;
    end

    -- local ok, result = pcall(func);
    local ok, result = commonlib.xpcall(func);
    if (not ok) then
        commonlib.LOG_WARN("ERROR: import failed:" .. filepath);
    else
        __module__.__module__ = result;
    end

    return __module__.__module__;
end



function commonlib.loadstring(chunk, env, chunkname, mode)
    if (type(chunk) ~= "string") then return nil, false end

    local func, errmsg = _G.load(chunk, chunkname or "dostring", mode or "bt", env or _G);

    if (not func) then
        commonlib.LOG_WARN("ERROR: loadstring->load " .. errmsg .. chunk);
    else
        return func, true;
    end

    return nil, false;
end

function commonlib.dostring(chunk, env, chunkname, mode, start_line)
    if (type(chunk) ~= "string") then return nil, false end
    if (start_line) then chunk = string.rep("\n", start_line, "") .. chunk end
    local func, errmsg = _G.load(chunk, chunkname or "dostring", mode or "bt", env or _G);
    if (not func) then
        commonlib.LOG_WARN("ERROR: dostring->load failed " .. errmsg .. "\n" .. chunk);
    else
        local ok, result = xpcall(func, function(xpcall_errmsg)
            commonlib.debug_traceback(nil, nil, xpcall_errmsg);
            return xpcall_errmsg;
        end);
        if (not ok) then
            commonlib.echo("ERROR: dostring->pcall failed " .. (result or ""));
        else
            return result, true;
        end
    end

    return nil, false;
end

return commonlib;